﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Web;
using System.Xml;
using NLUNZ;

namespace NLUNZ
{
    public class Repository
    {
        public static int SLIDESHOW_WIDTH = 960;
        public static int SLIDESHOW_HEIGHT = 278;
        public static int PARTNERIMG_WIDTH = 100;
        public static int PARTNERIMG_HEIGHT = 60;

        private static string webServiceUrl =
            ConfigurationManager.AppSettings["trackingApiUrl"];
            //"http://www.51kdd.com/api/xml/result/?com={0}&kw={1}&validate=&key=FREE-KEY-FGJ794GN";

        private static string DBConnection =
            ConfigurationManager.ConnectionStrings["NLUWebDBConnectionString"].ToString();

        #region slide images
        public static List<SlideImage> GetActiveSlideImages()
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            var slideImages = from s in context.SlideImages
                              where s.IsActive == true
                              orderby s.OrderNumber
                              select s;
            return slideImages.ToList();
        }

        #endregion

        #region partners

        public static List<Partner> GetAllPartners()
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            var partners = from p in context.Partners
                           where (p.showInHomePage == true)
                           select p;
            return partners.ToList();
        }

        public static void AddPartner(Partner partner)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            context.Partners.InsertOnSubmit(partner);
            context.SubmitChanges();
        }

        #endregion

        #region News

        public static List<CompanyInfo> GetLatestNews(int count)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            var news = (from n in context.CompanyInfos
                        orderby n.CreateDate descending
                        select n).Take(count);
            return news.ToList();
        }

        #endregion

        public static void AddBooking(Booking booking)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            context.Bookings.InsertOnSubmit(booking);
            context.SubmitChanges();
        }

        public static void SendEmail(string subject, string body)
        {
            var smtpServer = ConfigurationManager.AppSettings["smtpServer"];
            var smtpServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["smptServerPort"]);
            var emailAccount = ConfigurationManager.AppSettings["emailAccount"];
            var emailPassword = ConfigurationManager.AppSettings["emailPassword"];
            var adminEmail = ConfigurationManager.AppSettings["adminEmail"];


            var client = new SmtpClient(smtpServer, smtpServerPort)
                             {
                                 Credentials = new NetworkCredential(emailAccount, emailPassword),
                                 EnableSsl = true
                             };

            MailMessage message = new MailMessage(emailAccount, adminEmail, subject, body);
            client.Send(message);
        }

        public static TrackingItem DeliveryTrackingItemMapping(Delivery delivery)
        {

            TrackingItem item = new TrackingItem();

            //pickup
            item.PickupDateTime = delivery.ReceivedDateTime == null ? DateTime.MinValue : (DateTime)delivery.ReceivedDateTime;
            item.TIPickupBy = delivery.Recipient;

            //inventory in warehouse
            item.InventoryDateTime = delivery.InventoryDateTime == null
                                         ? DateTime.MinValue
                                         : (DateTime) delivery.InventoryDateTime;

            //arrival departure airport
            item.ArrivalDepartureAirportDateTime = delivery.AirportDateTime == null
                                       ? DateTime.MinValue
                                       : (DateTime) delivery.AirportDateTime;
            //delivery
            item.DeliveryToDestinationCountryCustomDateTime = delivery.DeliveryDateTime == null
                                        ? DateTime.MinValue
                                        : (DateTime) delivery.DeliveryDateTime;
            //custom
            item.ClearCustomDateTime = delivery.CustomDate == null ? DateTime.MinValue : (DateTime) delivery.CustomDate;


            item.TIDeliveryNumber = delivery.DeliveryNum;
            item.TIDeliveryCity = delivery.DeliveryCity;
            item.TICustom = delivery.Custom;

            #region courier delivery

            List<CourierTracking> couriers = new List<CourierTracking>();
            //get tracking details by deliverynumber
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);
            var trackings = from t in context.Trackings
                            where t.DeliveryNumber == delivery.DeliveryNum
                            select t;
            if(trackings.Count() != 0)
            {
                foreach (Tracking tracking in trackings)
                {
                    CourierTracking ct = new CourierTracking();
                    ct.CourierCode = tracking.CompanyCode;
                    ct.CourierCompanyName = tracking.Company.Name;
                    ct.CourierTrackingNumber = tracking.TrackingNumber;
                    ct.CourierDateTime = tracking.TrackingDateTime == null
                                             ? string.Empty
                                             : ((DateTime) tracking.TrackingDateTime).ToString("yyyy-MM-dd HH:ss:mm");
                    ct.CourierTrackingCode = tracking.Company.CompanyTrackingCode;
                    //ct.TrackingXML = GetTrackingXML(ct);
                    couriers.Add(ct);
                }
            }
            item.CourierTrackings = couriers;

            #endregion

            return item;
        }

        private static string GetTrackingXML(CourierTracking ct)
        {
            string apiKey = ConfigurationManager.AppSettings["TrackingApiKey"];
            string url = string.Format(webServiceUrl,apiKey, ct.CourierTrackingCode, ct.CourierTrackingNumber);

            WebResponse response;
            try
            {
                WebRequest request = WebRequest.Create(url);
                response = request.GetResponse();
            }
            catch (Exception)
            {
                return "ERROR: 数据传输中断， 请稍后重试。";
            }
            Stream stream = response.GetResponseStream();

            StreamReader reader = new StreamReader(stream);
            return reader.ReadToEnd();
        }

        public static string GetValueFromDictionary(string key)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            var value = context.Dictionaries.SingleOrDefault(d => d.Key.ToUpper() == key.ToUpper());

            return value == null ? string.Empty: value.Value;
        }

        public static CompanyInfo GetNewsById(int id)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            CompanyInfo news = context.CompanyInfos.SingleOrDefault(n => n.ID == id);
            return news;
        }

        public static bool ValidateUser(string text, string s)
        {
            return string.Equals(text, s, StringComparison.CurrentCultureIgnoreCase);
        }

        internal static void InsertSideshow(string title, string name, string url, string desc, string imgUrl)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            SlideImage slideImage = new SlideImage();
            slideImage.Title = title;
            slideImage.Name = name;
            slideImage.LinkUrl = url;
            slideImage.ImageUrl = imgUrl;
            slideImage.Description = desc;
            slideImage.CreateDate = DateTime.Now;
            slideImage.OrderNumber = 0;
            slideImage.IsActive = true;

            context.SlideImages.InsertOnSubmit(slideImage);
            context.SubmitChanges();
        }

        internal static void InsertPartner(string partnerTitle, string partnerUrl, string imgUrl)
        {
            NLUDBDataContext context = new NLUDBDataContext(DBConnection);

            Partner partner = new Partner();
            partner.Title = partnerTitle;
            partner.LinkUrl = partnerUrl;
            partner.ImageUrl = imgUrl;
            partner.showInHomePage = true;
            partner.CreateDate = DateTime.Now;
            context.Partners.InsertOnSubmit(partner);
            context.SubmitChanges();
        }

       public static List<Delivery> GetDeliveryById(List<string> deliveryId)
       {
           var context = new NLUDBDataContext(DBConnection);
           var deliveries = new List<Delivery>();
           foreach (string id in deliveryId)
           {
               Delivery delivery = context.Deliveries.SingleOrDefault(d => d.DeliveryNum == id.Trim());
               if(delivery != null)
                   deliveries.Add(delivery);
           }
           return deliveries;
       }

        public static bool DeliveryNumberExist(string deliveryNum)
        {
            var context = new NLUDBDataContext(DBConnection);
            var delivery = from d in context.Deliveries
                           where d.DeliveryNum == deliveryNum
                           select d;
            return delivery.Any();
        }

        public static bool InsertDeliveryRecordSuccess(Delivery delivery)
        {
            try
            {
                var context = new NLUDBDataContext(DBConnection);
                context.Deliveries.InsertOnSubmit(delivery);
                context.SubmitChanges();
            }
            catch(Exception ex)
            {
                return false;
            }
            return true;
        }

        public static bool UpdateDeliveryRecordSuccess(Delivery delivery)
        {
            try
            {
                var context = new NLUDBDataContext(DBConnection);
                Delivery existingRecord = context.Deliveries.Single(d => d.DeliveryNum == delivery.DeliveryNum);

                existingRecord.ReceivedDateTime = delivery.ReceivedDateTime;
                existingRecord.Recipient = delivery.Recipient;
                existingRecord.DeliveryCity = delivery.DeliveryCity;
                existingRecord.Custom = delivery.Custom;
                existingRecord.InventoryDateTime = delivery.InventoryDateTime;
                existingRecord.AirportDateTime = delivery.AirportDateTime;
                existingRecord.DeliveryDateTime = delivery.DeliveryDateTime;
                //existingRecord.CustomDate = delivery.CustomDate;

                context.SubmitChanges();
            }
            catch (Exception exception)
            {
                return false;
            }
            return true;
        }

        public static bool UpdateDeliveryRecordCustomInformation(Delivery delivery)
        {
            //only customDate and IsCheckedOut is updated
            try
            {
                var context = new NLUDBDataContext(DBConnection);
                Delivery existingDelivery = context.Deliveries.Single(d => d.DeliveryNum == delivery.DeliveryNum);

                existingDelivery.IsCheckedOut = delivery.IsCheckedOut;
                existingDelivery.CustomDate = delivery.CustomDate;

                context.SubmitChanges();
            }
            catch(Exception ex)
            {
                return false;
            }
            return true;
        }

        public static bool IsTrackingExist(string deliveryNumber, string trackingNumber)
        {
            var context = new NLUDBDataContext(DBConnection);
            var tracking = from t in context.Trackings
                                where t.DeliveryNumber == deliveryNumber && t.TrackingNumber == trackingNumber
                                select t;
            return tracking.Any();
        }

        public static bool InsertTrackingRecord(Tracking tracking, out string errorMessage)
        {
            try
            {
                var ctx = new NLUDBDataContext(DBConnection);
                ctx.Trackings.InsertOnSubmit(tracking);
                ctx.SubmitChanges();
            }
            catch (Exception ex)
            {
                errorMessage = ex.Message + ex.StackTrace;
                return false;
            }
            errorMessage = string.Empty;
            return true;
        }

        public static bool UpdateTrackingRecord(Tracking tracking)
        {
            try
            {
                var ctx = new NLUDBDataContext(DBConnection);
                Tracking trk = ctx.Trackings.Single(
                    t => t.DeliveryNumber == tracking.DeliveryNumber && t.TrackingNumber == tracking.TrackingNumber);
                trk.CompanyCode = tracking.CompanyCode;
                trk.TrackingDateTime = tracking.TrackingDateTime;

                ctx.SubmitChanges();
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }
    }

    public partial class CompanyInfo
    {
        public int SummaryLength = 50;
        public string Summary
        {
            get
            {
                int len = Content == null ? 0 : Content.Length;
                return Content == null? string.Empty : GetPlainTextFromHTMLContent(Content,len < SummaryLength ? len : SummaryLength);
            }
        }
        private static string GetPlainTextFromHTMLContent(string html,int numOfCharacters)
        {
            string result = string.Empty;
            if(numOfCharacters ==0)
            {
                StringBuilder allText = new StringBuilder();
                int count = 0;
                bool insideTag = false;
                while(count <= html.Length)
                {
                    if (html[count] == '<')
                    {
                        insideTag = true;
                    }
                    else if (html[count] == '>')
                    {
                        insideTag = false;
                    }else
                    {
                        if(!insideTag)
                        {
                            allText.Append(html[count]);
                        }
                    }
                    count++;
                }
                //return all the text
                result = allText.ToString();
            }
            else
            {
                StringBuilder summaryText = new StringBuilder();
                int count = 0;
                bool insideTag = false;
                while (count <= html.Length)
                {
                    if (html[count] == '<')
                    {
                        insideTag = true;
                    }
                    else if (html[count] == '>')
                    {
                        insideTag = false;
                    }
                    else
                    {
                        if (!insideTag)
                        {
                            summaryText.Append(html[count]);
                            if (summaryText.Length == numOfCharacters)
                                break;
                        }
                    }
                    count++;
                }
                result = summaryText.ToString();
            }
            return result;
        }
    }


    /// <summary>
    /// Recognize and process Images and get the image dimensions
    /// Supported Image format: JPG, GIF, PNG, BMP (bitmap)
    /// </summary>
    public static class ImageHelper
    {
        const string errorMessage = "Could not recognise image format.";
        private static Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDecoders = new Dictionary<byte[], Func<BinaryReader, Size>>()
        {
            { new byte[]{ 0x42, 0x4D }, DecodeBitmap},
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
            { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
            { new byte[]{ 0xff, 0xd8 }, DecodeJfif },
        };

        public static Size GetDimensions(string path)
        {
            using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)))
            {
                try
                {
                    return GetDimensions(binaryReader);
                }
                catch (ArgumentException e)
                {
                    if (e.Message.StartsWith(errorMessage))
                    {
                        throw new ArgumentException(errorMessage, "path", e);
                    }
                    else
                    {
                        throw e;
                    }
                }
            }
        }
        public static Size GetDimensions(BinaryReader binaryReader)
        {
            int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;

            byte[] magicBytes = new byte[maxMagicBytesLength];

            for (int i = 0; i < maxMagicBytesLength; i += 1)
            {
                magicBytes[i] = binaryReader.ReadByte();

                foreach (var kvPair in imageFormatDecoders)
                {
                    if (magicBytes.StartsWith(kvPair.Key))
                    {
                        return kvPair.Value(binaryReader);
                    }
                }
            }

            throw new ArgumentException(errorMessage, "binaryReader");
        }

        private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes)
        {
            for (int i = 0; i < thatBytes.Length; i += 1)
            {
                if (thisBytes[i] != thatBytes[i])
                {
                    return false;
                }
            }
            return true;
        }

        private static short ReadLittleEndianInt16(this BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(short)];
            for (int i = 0; i < sizeof(short); i += 1)
            {
                bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt16(bytes, 0);
        }

        private static int ReadLittleEndianInt32(this BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(int)];
            for (int i = 0; i < sizeof(int); i += 1)
            {
                bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt32(bytes, 0);
        }

        private static Size DecodeBitmap(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(16);
            int width = binaryReader.ReadInt32();
            int height = binaryReader.ReadInt32();
            return new Size(width, height);
        }

        private static Size DecodeGif(BinaryReader binaryReader)
        {
            int width = binaryReader.ReadInt16();
            int height = binaryReader.ReadInt16();
            return new Size(width, height);
        }

        private static Size DecodePng(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(8);
            int width = binaryReader.ReadLittleEndianInt32();
            int height = binaryReader.ReadLittleEndianInt32();
            return new Size(width, height);
        }

        private static Size DecodeJfif(BinaryReader binaryReader)
        {
            while (binaryReader.ReadByte() == 0xff)
            {
                byte marker = binaryReader.ReadByte();
                short chunkLength = binaryReader.ReadLittleEndianInt16();

                if (marker == 0xc0)
                {
                    binaryReader.ReadByte();

                    int height = binaryReader.ReadLittleEndianInt16();
                    int width = binaryReader.ReadLittleEndianInt16();
                    return new Size(width, height);
                }

                binaryReader.ReadBytes(chunkLength - 2);
            }

            throw new ArgumentException(errorMessage);
        }

    }

    public class TrackingItem
    {

        public string TIDeliveryNumber { get; set; }

        public string TIDeliveryCity { get; set; }

        public string TICustom { get; set; }


        #region Received - recipient pickup goods
        private string _recipient;

        public string TIPickupBy
        {
            get { return String.Format("取货员 <b>{0}</b> 取货", _recipient); }
            set { _recipient = value; }
        }
        public DateTime PickupDateTime { get; set; } //receiveddate and receivedtime
        #endregion

        #region Inventory - goods arrive warehouse
        public string InventoryDescription = "货件到达仓库";
        public DateTime InventoryDateTime { get; set; } //inventorydate and inventorytime

        #endregion

        #region Arrival departure Airport
        public string ArrivalDepartureAirportDescription = "货件到达货运机场";
        public DateTime ArrivalDepartureAirportDateTime { get; set; } //airportdate and airporttime
        #endregion

        #region Left departure City, heading destination country custom
        public string DeliveryToDestinationCountryCustom
        {
            get
            {
                string output = string.Format("快件已离开 <b>{0}</b>, 正前往 <b>{1}</b>", TIDeliveryCity, TICustom);
                return output;
            }
        }
        public DateTime DeliveryToDestinationCountryCustomDateTime { get; set; } //deliverydate and deliverytime
        #endregion

        #region arrival destination custom, awaiting custom clear
        //add 36 hours for arrival custom date
        public string ArrivalDestinationCountryCustom
        {
            get
            {
                string output = string.Format("快件已到达 <b>{0}</b>, 正在办理清关手续", TICustom);
                return output;
            }
        }

        private DateTime _arriveCustomDateTime = DateTime.MinValue;
        public DateTime ArrivalDestinationCountryCustomDateTime
        {
            get
            {
                if (DeliveryToDestinationCountryCustomDateTime != DateTime.MinValue)
                    _arriveCustomDateTime = DeliveryToDestinationCountryCustomDateTime.AddHours(36);
                return _arriveCustomDateTime;
            }
        }

        #endregion

        #region leave destination country custom, heading courier company
        //leave custom date
        public string ClearCustom
        {
            get
            {
                string output = string.Format("快件已离开 <b>{0}</b>, 正前往快递公司", TICustom);
                return output;
            }
        }
        public DateTime ClearCustomDateTime { get; set; }
        #endregion

        #region Arrive courier company

        public List<CourierTracking> CourierTrackings { get; set; }

        #endregion
    }

    public class CourierTracking
    {
        public string CourierCompanyName { get; set; }
        public string CourierDateTime { get; set; }
        public string CourierCode { get; set; }
        public string CourierTrackingNumber { get; set; }
        //public string TrackingXML { get; set; }
        public string CourierTrackingCode { get; set; }
    }

    public class Utility
    {
        public static DataSet ExcelToDataSet(string opnFileName)
        {
            //provider ACE.OLEDB.12.0 is for Excel 2007, but some hosting is not supported//
            //string strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + opnFileName + ";Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\"";
            string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + opnFileName + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1\"";
            OleDbConnection conn = new OleDbConnection(strConn);
            string strExcel = "";
            OleDbDataAdapter myCommand = null;
            DataSet ds = new DataSet();
            strExcel = "select * from [sheet1$]";
            try
            {
                conn.Open();
                myCommand = new OleDbDataAdapter(strExcel, strConn);
                myCommand.Fill(ds, "dtSource");
                return ds;
            }
            catch (Exception ex)
            {
                string err = "导入出错：" + ex + ", 错误信息";
                return ds;
            }
            finally
            {
                conn.Close();
                conn.Dispose();
            }
        }
        public static bool IsExcel(string FileName)
        {

            try
            {
                //取得文件名(抱括路径)里最后一个"."的索引
                int intExt = FileName.LastIndexOf(".");
                //取得文件扩展名
                string strExt = FileName.Substring(intExt);
                if (strExt.ToLower() == ".xls" || strExt.ToLower() == ".xlsx")
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }
        public static string NewFileName(string FileName, string serverDestinationPath)
        {


            //这里自动根据日期和文件大小不同为文件命名,确保文件名不重复
            DateTime datNow = DateTime.UtcNow.AddHours(+12);
            //string strNewName = DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + FileName ;
            string strNewName = datNow.ToString("yyyyMMddHHmmss") + "_" + FileName;
            string strPath = serverDestinationPath + strNewName;
            return strPath;
        }

        public static object LockingTarget = new object();

        public static void LogToFile(HttpServerUtility server, string message)
        {
            lock(LockingTarget)
            {
                string path = server.MapPath("~/Upload/Logs/log.txt");
                StreamWriter writer = new StreamWriter(path,true);
                writer.Write(String.Format("{0}:{1}",DateTime.UtcNow.AddHours(12),message));
            }
        }
        public void LogToFile(string message)
        {
            lock (LockingTarget)
            {
                string path = @"D:\Hosting\4503735\html\Upload\Logs\log.txt";
                StreamWriter writer = new StreamWriter(path, true);
                writer.Write(String.Format("{0}:{1}", DateTime.UtcNow.AddHours(12), message));
            }
        }
    }
}